-- 1. rateLimiterKey redis key
-- 2. permitsPerSecond  每秒存入的令牌数
-- 3. maxBurstSeconds   总共多少秒 （最大存储 maxBurstSeconds 秒生成的令牌）
-- 4. needPermits 获取的令牌数
-- 5. currentMillis 当前的时间戳
local rateLimiterKey, permitsPerSecond, maxBurstSeconds, needPermits, currentMillis = KEYS[1], tonumber(ARGV[1]), tonumber(ARGV[2]), tonumber(ARGV[3]), tonumber(ARGV[4])
local rateLimiterPermits = redis.call('HGETALL', rateLimiterKey)
--  tempMaxPermits 当前存储的令牌
local tempMaxPermits = permitsPerSecond * maxBurstSeconds
--  returnValue
--  nextFreeTicketMillis 下次获取令牌的时间
local maxPermits, stableIntervalMillis, storedPermits, nextFreeTicketMillis, returnValue

if table.maxn(rateLimiterPermits) >= 8 then
  maxPermits, stableIntervalMillis, storedPermits, nextFreeTicketMillis = tonumber(rateLimiterPermits[2]), tonumber(rateLimiterPermits[4]), tonumber(rateLimiterPermits[6]), tonumber(rateLimiterPermits[8])

  -- The current limiting strategy has changed
  -- 限流策略变了 重新计算所有的值
  if 0.5 < math.abs(maxPermits - tempMaxPermits) then
    maxPermits, stableIntervalMillis = tempMaxPermits, 1000.00 / permitsPerSecond
    storedPermits, nextFreeTicketMillis = permitsPerSecond, currentMillis
  end
else
  -- 第一次，初始化
  -- stableIntervalMillis  一个令牌生成的需要间隙时间
  maxPermits, stableIntervalMillis = tempMaxPermits, 1000.00 / permitsPerSecond
  storedPermits, nextFreeTicketMillis, returnValue = permitsPerSecond, currentMillis, currentMillis
end

-- Current time has exceeded（超过） the most recent available time, reset,
if currentMillis > nextFreeTicketMillis then
  storedPermits = math.min(maxPermits, storedPermits + (currentMillis - nextFreeTicketMillis) / stableIntervalMillis);
  nextFreeTicketMillis = currentMillis
end

-- 下次生成令牌的时间
returnValue = nextFreeTicketMillis

-- 获取的令牌和存储的令牌最小值，计算等待时间
local storedPermitsToSpend = math.min(needPermits, storedPermits)
-- 计算是否需要创建新令牌
local freshPermits = needPermits - storedPermitsToSpend
-- 计算等待时间
local waitMillis = math.floor(freshPermits * stableIntervalMillis)
-- 存储下个时间戳
nextFreeTicketMillis = returnValue + waitMillis
-- 更新令牌数
storedPermits = storedPermits - storedPermitsToSpend
-- 存储到redis 中
redis.call('HMSET', rateLimiterKey, 'maxPermits', maxPermits, 'stableIntervalMicros', stableIntervalMillis, 'storedPermits', storedPermits, 'nextFreeTicketMillis', nextFreeTicketMillis)

-- 1 min
redis.call('EXPIRE', rateLimiterKey, 60)
-- 返回等待时间
return math.max(returnValue - currentMillis, 0)